package de.fhkl.strokeserver;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import de.fhkl.strokeserver.core.MySQLConnection;
import de.fhkl.strokeserver.core.StrokeServer;
import de.fhkl.strokeserver.user.User;
import de.fhkl.strokeserver.util.Utilities;

/**
 * Servlet implementation class Server
 */
@WebServlet(urlPatterns = { "/Server" })
public class Server extends HttpServlet
{
	private static final long serialVersionUID = -3242328368738366561L;
	
	// Pages for the requestDispatcher to forward 
	private static final String PAGE_INDEX = "/index.jsp";
	private static final String PAGE_MAIN = "/main.jsp";
	
	// Session attribute which indicated if the server is running
	private static final String ATTRIBUTE_RUN = "run";
	
	// Indicates if the session holds an admin
	private static final String ATTRIBUTE_ADMIN = "admin";
	
	// Actions which are requested from an user action
	private static final String ACTION_START = "start";
	private static final String ACTION_STOP = "stop";
	private static final String ACTION_RESTART = "restart";
	private static final String ACTION_LOGIN = "login";
	private static final String ACTION_LOGOUT = "logout";
	private static final String ACTION_INSERT = "insert";
	private static final String ACTION_DELETE = "delete";
	
	// Message Attributes which are shown after a request
	private static final String ATTRIBUTE_LOGIN_MESSAGE = "message";
	private static final String ATTRIBUTE_DATABASE_MESSAGE = "dbMessage";
	private static final String ATTRIBUTE_DATABASE_ERROR = "dbError";
	private static final String ATTRIBUTE_SERVER_MESSAGE = "serverMessage";
	private static final String ATTRIBUTE_EMPTY_TYPE = "emptyType";
	private static final String ATTRIBUTE_WRONG_EMAIL = "wrongEmail";
	private static final String ATTRIBUTE_WRONG_PASSWORD = "wrongPassword";
	private static final String ATTRIBUTE_PASSWORDS_DONT_MATCH = "passwordsDontMatch";
	
	// Parameters for database requests
	private static final String PARAMETER_USERID = "id";
	private static final String PARAMETER_TYPE = "type";
	private static final String PARAMETER_EMAIL = "email";
	private static final String PARAMETER_PASSWORD = "password";
	private static final String PARAMETER_REPEAT_PASSWORD = "repeatpw";
	
	// Attribute which holds the list of all users
	private static final String ATTRIBUTE_ALL_USERS = "allUsers";

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public Server()
	{
		super();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		request.getRequestDispatcher(PAGE_INDEX).forward(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		HttpSession session = request.getSession(true);
		String action = request.getParameter("action").toLowerCase();

		// check if admin is logged in or wants to login
		if (session.getAttribute(ATTRIBUTE_ADMIN) != null && !session.getAttribute(ATTRIBUTE_ADMIN).toString().isEmpty()
				|| action.equals(ACTION_LOGIN))
		{
			if (action.equals(ACTION_START))
			{
				startServer(request, response, session);
			}
			else if (action.equals(ACTION_STOP))
			{
				stopServer(request, response, session);
			}
			else if (action.equals(ACTION_RESTART))
			{
				restartServer(request, response, session);
			}
			else if (action.equals(ACTION_LOGIN))
			{
				login(request, response, session);
			}
			else if (action.equals(ACTION_LOGOUT))
			{
				logout(request, response, session);
			}
			else if (action.equals(ACTION_INSERT))
			{
				insertUser(request, response, session);
			}
			else if (action.equals(ACTION_DELETE))
			{
				deleteUser(request, response, session);
			}
		}
		else
		{
			request.getRequestDispatcher(PAGE_INDEX).forward(request, response);
		}
	}

	private void startServer(HttpServletRequest request, HttpServletResponse response, HttpSession session)
			throws ServletException, IOException
	{
		if (StrokeServer.getInstance().start())
		{
			session.setAttribute(ATTRIBUTE_RUN, StrokeServer.isRunning());
			request.setAttribute(ATTRIBUTE_SERVER_MESSAGE, "Server successfully started on port " + StrokeServer.getPort() + ".");
			request.getRequestDispatcher(PAGE_MAIN).forward(request, response);
		}
	}

	private void stopServer(HttpServletRequest request, HttpServletResponse response, HttpSession session)
			throws ServletException, IOException
	{
		StrokeServer.getInstance().stop();
		session.setAttribute(ATTRIBUTE_RUN, StrokeServer.isRunning());
		request.setAttribute(ATTRIBUTE_SERVER_MESSAGE, "Server successfully stopped.");
		request.getRequestDispatcher(PAGE_MAIN).forward(request, response);
	}

	private void restartServer(HttpServletRequest request, HttpServletResponse response, HttpSession session)
			throws ServletException, IOException
	{
		StrokeServer.getInstance().stop();
		if (StrokeServer.getInstance().start())
		{
			session.setAttribute(ATTRIBUTE_RUN, StrokeServer.isRunning());
			request.setAttribute(ATTRIBUTE_SERVER_MESSAGE, "Server successfully stopped. Server successfully started on port "
					+ StrokeServer.getPort() + ".");
			request.getRequestDispatcher(PAGE_MAIN).forward(request, response);
		}
	}

	private void login(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws ServletException,
			IOException
	{
		String email = request.getParameter(PARAMETER_EMAIL);
		String password = request.getParameter(PARAMETER_PASSWORD);
		
		User admin = null;
		
		if (password != null)
		{
			password = Utilities.generateMd5Sum(password);
			admin = MySQLConnection.getUser(email, password, 'a');
		}

		if (admin != null)
		{
			if (StrokeServer.isRunning())
			{
				request.setAttribute(ATTRIBUTE_SERVER_MESSAGE, "Server successfully started on port " + StrokeServer.getPort() + ".");
			}
			session.setAttribute(ATTRIBUTE_RUN, StrokeServer.isRunning());
			session.setAttribute(ATTRIBUTE_ADMIN, admin);
			session.setAttribute(ATTRIBUTE_ALL_USERS, MySQLConnection.getAllUsers());
			request.getRequestDispatcher(PAGE_MAIN).forward(request, response);
		}
		else
		{
			request.setAttribute(ATTRIBUTE_LOGIN_MESSAGE, "Bad credentials!");
			request.getRequestDispatcher(PAGE_INDEX).forward(request, response);
		}
	}

	private void logout(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws ServletException,
			IOException
	{
		session.setAttribute(ATTRIBUTE_ADMIN, null);
		request.getRequestDispatcher(PAGE_INDEX).forward(request, response);
	}

	private void insertUser(HttpServletRequest request, HttpServletResponse response, HttpSession session)
			throws ServletException, IOException
	{
		String type = request.getParameter(PARAMETER_TYPE);
		String email = request.getParameter(PARAMETER_EMAIL);
		String password = request.getParameter(PARAMETER_PASSWORD);
		boolean correct = true;

		if (type == null || type.isEmpty())
		{
			correct = false;
			request.setAttribute(ATTRIBUTE_EMPTY_TYPE, "Type required!");
		}

		if (email == null || email.isEmpty())
		{
			correct = false;
			request.setAttribute(ATTRIBUTE_WRONG_EMAIL, "Email required!");
		}
		else if (!email.contains("@"))
		{
			correct = false;
			request.setAttribute(ATTRIBUTE_WRONG_EMAIL, "Invalid email!");
		}

		if (password != null && !password.isEmpty())
		{
			if (password.length() < 6)
			{
				correct = false;
				request.setAttribute(ATTRIBUTE_WRONG_PASSWORD, "Password length must be greater than 6 characters!");
			}
			else if (!password.equals(request.getParameter(PARAMETER_REPEAT_PASSWORD)))
			{
				correct = false;
				request.setAttribute(ATTRIBUTE_PASSWORDS_DONT_MATCH, "Passwords don't match!");
			}
		}
		else
		{
			correct = false;
			request.setAttribute(ATTRIBUTE_WRONG_PASSWORD, "Password required!");
		}

		if (correct)
		{
			int count = MySQLConnection.insertUser(email, password, type);
			if (count > 0)
			{
				request.setAttribute(ATTRIBUTE_DATABASE_MESSAGE, "User inserted!");
				session.setAttribute(ATTRIBUTE_ALL_USERS, MySQLConnection.getAllUsers());
			}
			else if (count == 0)
			{
				request.setAttribute(ATTRIBUTE_WRONG_EMAIL, "Email already in use!");
			}
			else
			{
				request.setAttribute(ATTRIBUTE_DATABASE_ERROR, "An error occured while inserting user!");
			}
		}

		request.getRequestDispatcher(PAGE_MAIN).forward(request, response);
	}

	private void deleteUser(HttpServletRequest request, HttpServletResponse response, HttpSession session)
			throws ServletException, IOException
	{
		int count = MySQLConnection.deleteUser(request.getParameter(PARAMETER_USERID));
		
		if (count > 0)
		{
			request.setAttribute(ATTRIBUTE_DATABASE_MESSAGE, "User deleted!");
			session.setAttribute(ATTRIBUTE_ALL_USERS, MySQLConnection.getAllUsers());
		}
		else
		{
			request.setAttribute(ATTRIBUTE_DATABASE_ERROR, "An error occured while deleting user!");
		}
			
		request.getRequestDispatcher(PAGE_MAIN).forward(request, response);
	}
}
